//
//  Integrator.hpp
//  RayTracer
//
//  Created by 俞云康 on 2/15/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#ifndef Integrator_hpp
#define Integrator_hpp

#include "Math.hpp"
#include "Scene.hpp"
#include "Camera.hpp"

class Params;

class Renderer;

class Integrator {
public:
	virtual ~Integrator();
	//virtual void render(const Scene &scene) = 0;
};

class SamplerIntegrator : public Integrator {
public:
	SamplerIntegrator(shared_ptr<const Camera> camera, shared_ptr<Sampler> sampler)
		: m_camera(camera), m_sampler(sampler) {}

	virtual void preprocess(const Scene &scene, Sampler &sampler) { }
	//virtual void render(cosnt )
	virtual Color Li(const Ray &ray, const Scene &scene, Sampler &sampler, int depth = 0) const = 0;
	Color SpecularReflect (const Ray &ray, const HitInfo& hit, const Scene &scene, Sampler &sampler, int depth) const;
	Color SpecularTransmit(const Ray &ray, const HitInfo& hit, const Scene &scene, Sampler &sampler, int depth) const;

protected:
	shared_ptr<const Camera> m_camera;
private:
	shared_ptr<Sampler> m_sampler;
};

class SurfaceIntegrator
{
public:
    virtual ~SurfaceIntegrator() {}
    
    static shared_ptr<SurfaceIntegrator> create(const Params& params);
    
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const = 0;
};

class NormalIntegrator : public SurfaceIntegrator {
public:
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
};

class DepthIntegrator : public SurfaceIntegrator {
public:
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
};

class AmbientOcclusion : public SurfaceIntegrator {
public:
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
private:
    int n_samples = 2048;
    float max_t = 20.f;
};

class PathIntegrator : public SurfaceIntegrator {
public:
	virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
private:
	float m_maxDepth = 5;
};

class DirectLightingIntegrator : public SurfaceIntegrator {
public:
	DirectLightingIntegrator(const int maxDepth) : m_maxDepth(maxDepth) {}
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
private:
    int m_maxDepth = 5;
};

class DirectIlluminationIngetrator : public SurfaceIntegrator {
public:
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
};

class WhittedIntegrator : public SurfaceIntegrator {
public:
    virtual Color Li(const Scene& scene, const Renderer& renderer, const Ray& ray, const HitInfo& hit, Sampler& sampler, RNG& rng) const override;
private:
    int m_maxDepth = 5;
};

#endif /* Integrator_hpp */
